package com.util.zip;

import org.apache.commons.compress.archivers.zip.ScatterZipOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntryRequest;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.parallel.InputStreamSupplier;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutionException;

/**
 * 多线程并行输出流 <br>
 * date：2020-12-26 13:57
 *
 * @author yuanweilin
 * @version 1.0
 * @since JDK 1.8
 */
public class ZipScatterOutputStream {

    /**
     * 需要 压缩文件/文件夹 路径
     */
    private String directoryPath;
    /**
     *
     */
    private final ZipCreator creator;
    /**
     * 多线程输出流
     */
    private final ScatterZipOutputStream output;

    public ZipScatterOutputStream(String directoryPath) throws IOException {
        this(directoryPath, Runtime.getRuntime().availableProcessors());
    }

    public ZipScatterOutputStream(String directoryPath, int nThreads) throws IOException {
        this.directoryPath = directoryPath;
        this.creator = new ZipCreator(nThreads);
        this.output = ScatterZipOutputStream.fileBased(File.createTempFile("whatever-preffix", ".whatever"));
    }

    public void addEntry(ZipArchiveEntry entry, InputStreamSupplier supplier) throws IOException {
        if (entry.isDirectory() && !entry.isUnixSymlink()) {
            output.addArchiveEntry(ZipArchiveEntryRequest.createZipArchiveEntryRequest(entry, supplier));
        } else {
            creator.addArchiveEntry(entry, supplier);
        }
    }

    public void writeTo(ZipArchiveOutputStream archiveOutput) throws IOException, ExecutionException, InterruptedException {
        output.writeTo(archiveOutput);
        output.close();
        creator.writeTo(archiveOutput);
    }

    public String getDirectoryPath() {
        return directoryPath;
    }

    public ZipCreator getCreator() {
        return creator;
    }

    public ScatterZipOutputStream getOutput() {
        return output;
    }
}
